package dao

import (
	"context"
	"errors"
	"github.com/go-sql-driver/mysql"
	"gorm.io/gorm"
	"time"
)

var (
	ErrUserDuplicateEmail = errors.New("邮箱冲突")
	ErrUserNotFound       = gorm.ErrRecordNotFound
)

type UserDAO struct {
	db *gorm.DB
}

func NewUserDAO(db *gorm.DB) *UserDAO {
	return &UserDAO{
		db: db,
	}
}

func (dao *UserDAO) FindByEmail(context context.Context, email string) (User, error) {
	var u User
	err := dao.db.WithContext(context).Where("email = ?", email).First(&u).Error
	//err := dao.db.WithContext(context).First(&u, "email = ?", email).Error
	return u, err
}

// 一定会有context作为参数，error作为返回值，现在不用深究
// 参数中尽量传结构体，约定俗成
func (dao *UserDAO) Insert(context context.Context, u User) error {
	//这里进行初始化
	//存毫秒数
	now := time.Now().UnixMilli()
	u.Utime = now
	u.Ctime = now
	err := dao.db.WithContext(context).Create(&u).Error
	//这里和底层强耦合，但因为一般不会频繁更换数据库类型，所以还好
	if mysqlErr, ok := err.(*mysql.MySQLError); ok {
		const uniqueConflictErrNo uint16 = 1062
		if mysqlErr.Number == uniqueConflictErrNo {
			//邮箱冲突，只有一个唯一索引
			return ErrUserDuplicateEmail
		}
	}
	return err
}

// User直接对应数据库表结构
// 有些人叫做entity， 有些人叫做model，有些人叫做PO（persistent object）
// dao 里面操作的并不是domain.User，而是定义了一个新的类型。
type User struct {
	Id int64 `gorm:"primaryKey,autoIncrement"`
	//全部用户唯一
	Email    string `gorm:"unique"`
	Password string
	//往这里面加

	//创建时间， 毫秒数
	Ctime int64
	//更新时间, 毫秒数
	Utime int64
}
